package io.xxx.xbutler.core.get;

import com.alibaba.fastjson2.JSON;
import io.xxx.xbutler.client.PromotionClient;
import io.xxx.xbutler.common.RedisKeys;
import io.xxx.xbutler.domain.RedEnvelope;
import io.xxx.xbutler.domain.task.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RSetCache;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class RedEnvelopeGetter implements ContentGetter {

    @Resource
    private PromotionClient promotionClient;

    @Resource
    private RedissonClient redissonClient;

    @Value("${red-envelope.active-time:24}")
    private int activeTime;

    @Override
    public void replaceContent(PushContext context) {
        Task task = context.getTask();
        Long taskId = task.getId();
        Receiver receiver = context.getReceiver();
        Long storeId = receiver.getStoreId();
        String storeCode = receiver.getStoreCode();
        List<TaskItem> taskItems = context.getTaskItems();
        for (TaskItem taskItem : taskItems) {
            if (!taskItem.assign(MessageType.MINI_PROGRAM, ContentType.RED_ENVELOPE)) {
                continue;
            }
            Long taskItemId = taskItem.getId();

            RSetCache<Long> storeUsedRedEnvelopesSet = redissonClient.getSetCache(RedisKeys.storeUsedRedEnvelopes(storeId));
            RBucket<Long> storeCurrentUsedRedEnvelopeBucket = redissonClient.getBucket(RedisKeys.storeCurrentUsedRedEnvelope(storeId, LocalDate.now()));

            Long usedRedEnvelopeId = storeCurrentUsedRedEnvelopeBucket.get();
            if (usedRedEnvelopeId == null) {    // 当天未发送红包
                List<RedEnvelope> redEnvelopes = promotionClient.getRedEnvelopes(storeId);
                Optional<RedEnvelope> optional = redEnvelopes.stream()
                        .filter(it -> {
                            LocalDateTime receiveEndTime = it.getReceiveEndTime();
                            Duration between = Duration.between(receiveEndTime, LocalDateTime.now()).abs();
                            long hours = between.toHours();
                            if (hours < activeTime) {
                                log.info("门店红包有限期小于阈值[taskId:{}, taskItemId:{}. storeId:{}, storeCode:{}, redEnvelopedId:{}, activateTime:{}, remainingActivateTime:{}]",
                                        taskId, taskItemId, storeId, storeCode, it.getId(), activeTime, hours);
                                return false;
                            }
                            if (it.getRemainingQuantity() == 0) {
                                log.warn("门店红包已经领取完毕[taskId:{}, taskItemId:{}, storeId:{}, storeCode:{}, redEnvelopeId:{}]",
                                        taskId, taskItemId, storeId, storeCode, it.getId());
                                return false;
                            }

                            Long redEnvelopeId = it.getId();
                            if (storeUsedRedEnvelopesSet.contains(redEnvelopeId)) {
                                log.info("门店红包已经被使用[taskId:{}, taskItemId:{}. storeId:{}, storeCode:{}, redEnvelopeId:{}, usedRedEnvelopeIds:{}]",
                                        taskId, taskItemId, storeId, storeCode, redEnvelopeId, storeUsedRedEnvelopesSet);
                                return false;
                            }

                            return true;
                        })
                        .min(Comparator.comparing(RedEnvelope::getReceiveEndTime));
                if (optional.isPresent()) {
                    RedEnvelope redEnvelope = optional.get();
                    storeUsedRedEnvelopesSet.add(redEnvelope.getId(), 60, TimeUnit.DAYS);   // 红包最长有效期为30天
                    storeCurrentUsedRedEnvelopeBucket.set(redEnvelope.getId(), Duration.ofDays(1));
                    RBucket<String> redEnvelopeBucket = redissonClient.getBucket(RedisKeys.redEnvelope(redEnvelope.getId()));
                    redEnvelopeBucket.set(JSON.toJSONString(redEnvelope), Duration.ofDays(1));

                    taskItem.setContent(ContentGetter.buildMiniProgram(redEnvelope.getTitle(), redEnvelope.getThumbUrl(), redEnvelope.getPagePath()));
                }
            } else {    // 当天已发送过红包
                RBucket<String> redEnvelopeBucket = redissonClient.getBucket(RedisKeys.redEnvelope(usedRedEnvelopeId));
                if (!StringUtils.hasText(redEnvelopeBucket.get())) {
                    log.error("红包信息缓存不存在[taskId:{}, taskItemId:{}. storeId:{}, storeCode:{}, redEnvelopeId:{}]",
                            taskId, taskItemId, storeId, storeCode, usedRedEnvelopeId);
                    continue;
                }

                RedEnvelope redEnvelope = promotionClient.getRedEnvelope(usedRedEnvelopeId);
                if (redEnvelope == null) {
                    log.error("红包信息不存在[taskId:{}, taskItemId:{}. storeId:{}, storeCode:{}, redEnvelopeId:{}]",
                            taskId, taskItemId, storeId, storeCode, usedRedEnvelopeId);
                    continue;
                }
                if (redEnvelope.getRemainingQuantity() == 0) {
                    log.warn("门店红包已经领取完毕[taskId:{}, taskItemId:{}, storeId:{}, storeCode:{}, redEnvelopeId:{}]",
                            taskId, taskItemId, storeId, storeCode, redEnvelope.getId());
                    continue;
                }

                taskItem.setContent(ContentGetter.buildMiniProgram(redEnvelope.getTitle(), redEnvelope.getThumbUrl(), redEnvelope.getPagePath()));
            }
        }
    }
}
